package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cmc.cloud.cmclink.doc.api.document.emums.CntrSizeEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.CntrTypeEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.SpecialEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.SpecialCargoFlexiErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.SpecialCargoOogErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.SpecialCargoOogConvert;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.*;
import com.cmc.cloud.cmclink.doc.service.SpecialCargoOogService;
import com.cmc.cloud.cmclink.doc.util.CostChargeUtil;
import com.cmc.cloud.cmclink.doc.util.I18nsUtil;
import com.cmc.cloud.cmclink.doc.vo.specialcargooogvo.*;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 特种货审批oog Service 实现类
 *
 * @author 集运管理员
 */
@Service
@Validated
public class SpecialCargoOogServiceImpl implements SpecialCargoOogService {

    @Resource
    private SpecialCargoOogMapper specialCargoOogMapper;
    @Resource
    private SpecialCargoCntrMapper specialCargoCntrMapper;
    @Resource
    private ContainerMaxPayloadMapper containerMaxPayloadMapper;
    @Resource
    private PortTerminalMaxArgMapper portTerminalMaxArgMapper;
    @Resource
    private CostChargeUtil costChargeUtil;
    @Resource
    private I18nsUtil i18nsUtil;
    @Resource
    private SpecialCargoApplyMapper specialCargoApplyMapper;
    @Resource
    private SpecialCargoVoyageMapper specialCargoVoyageMapper;

    private static final int DEFAULT_INT_VALUE = 0;


    @Override
    public void createSpecialCargoOog(SpecialCargoOogCreateReqVO createReqVO) {
        // 插入
        SpecialCargoOogDO specialCargoOog = SpecialCargoOogConvert.INSTANCE.convert(createReqVO);
        specialCargoOogMapper.insert(specialCargoOog);
    }

    @Override
    public void updateSpecialCargoOog(SpecialCargoOogUpdateReqVO updateReqVO) {
        // 校验存在
        validateSpecialCargoOogExists(updateReqVO.getId());
        // 更新
        SpecialCargoOogDO updateObj = SpecialCargoOogConvert.INSTANCE.convert(updateReqVO);
        specialCargoOogMapper.updateById(updateObj);
    }

    @Override
    public void deleteSpecialCargoOog(Long id) {
        // 校验存在
        validateSpecialCargoOogExists(id);
        // 删除
        specialCargoOogMapper.deleteById(id);
    }

    private void validateSpecialCargoOogExists(Long id) {
        if (specialCargoOogMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_NOT_EXISTS);
        }
    }

    @Override
    public SpecialCargoOogDO getSpecialCargoOog(Long id) {
        LambdaQueryWrapperX<SpecialCargoOogDO> oogQuery = new LambdaQueryWrapperX<SpecialCargoOogDO>().eq(SpecialCargoOogDO::getCntrId, id).orderByDesc(SpecialCargoOogDO::getCreateTime).last("LIMIT 1");
        return specialCargoOogMapper.selectOne(oogQuery);
    }

    @Override
    public List<SpecialCargoOogDO> getSpecialCargoOogList(Collection<Long> ids) {
        return specialCargoOogMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<SpecialCargoOogDO> getSpecialCargoOogPage(SpecialCargoOogPageReqVO reqVO) {
        IPage<SpecialCargoOogDO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());

        IPage<SpecialCargoOogDO> result = specialCargoOogMapper.selectPageList(page, reqVO);
        return new PageResult<>(result.getRecords(), result.getTotal());
    }

    @Override
    public void createPortTerminalMaxArg(PortTerminalMaxArgBaseVO createReqVO) {
        // 插入
        PortTerminalMaxArgDO portTerminalMaxArgDo = portTerminalMaxArgMapper.selectOne(new LambdaQueryWrapper<PortTerminalMaxArgDO>()
                .eq(PortTerminalMaxArgDO::getTerminalCode, createReqVO.getTerminalCode())
                .eq(PortTerminalMaxArgDO::getPort, createReqVO.getPort())
                .eq(PortTerminalMaxArgDO::getCntrType, createReqVO.getCntrType())
                .eq(PortTerminalMaxArgDO::getCntrSize, createReqVO.getCntrSize())
                .eq(PortTerminalMaxArgDO::getEnable, Boolean.TRUE));
        if (null != portTerminalMaxArgDo) {
            throw ServiceExceptionUtil.exception(SpecialCargoOogErrorCodeConstants.OOG_PORT_TERMINAL_MAX_ARG_ERROR);
        }
        PortTerminalMaxArgDO portTerminalMaxArg = SpecialCargoOogConvert.INSTANCE.convert(createReqVO);
        portTerminalMaxArgMapper.insert(portTerminalMaxArg);
    }

    @Override
    public void updatePortTerminalMaxArg(PortTerminalMaxArgBaseVO updateReqVo) {
        // 更新
        PortTerminalMaxArgDO updateObj = SpecialCargoOogConvert.INSTANCE.convert(updateReqVo);
        portTerminalMaxArgMapper.updateById(updateObj);
    }

    @Override
    public void deletePortTerminalMaxArg(Long id) {
        // 删除
        portTerminalMaxArgMapper.deleteById(id);
    }

    @Override
    public PortTerminalMaxArgDO getPortTerminalMaxArg(Long id) {
        return portTerminalMaxArgMapper.selectById(id);
    }

    @Override
    public PageResult<PortTerminalMaxArgBaseVO> getPortTerminalMaxArgPage(PortTerminalMaxArgPageReqVO reqVO) {
        LambdaQueryWrapper<PortTerminalMaxArgDO> queryWrapperX = new LambdaQueryWrapper<PortTerminalMaxArgDO>().like(PortTerminalMaxArgDO::getPort, reqVO.getPort()).orderByDesc(PortTerminalMaxArgDO::getCreateTime);
        PageResult<PortTerminalMaxArgDO> pageResult = portTerminalMaxArgMapper.selectPage(reqVO, queryWrapperX);
        List<PortTerminalMaxArgBaseVO> results = BeanUtil.copyToList(pageResult.getList(), PortTerminalMaxArgBaseVO.class);
        return new PageResult<>(results, pageResult.getTotal());
    }

    @Override
    public String checkMaxArg(Long applyId, Long voyageId) {
        SpecialCargoApplyDO applyDo = specialCargoApplyMapper.selectById(applyId);
        Locale currentLocale = LocaleContextHolder.getLocale();
        if (SpecialEnum.FLEXI.getValue().equals(applyDo.getApplyType())) {
            List<SpecialCargoCntrDO> cntrList = specialCargoCntrMapper.selectList(new LambdaQueryWrapper<SpecialCargoCntrDO>()
                    .eq(SpecialCargoCntrDO::getApplyId, applyId));
            if (CollectionUtil.isEmpty(cntrList)) {
                return StringUtils.EMPTY;
            }
            List<String> cntrSizes = cntrList.stream().map(SpecialCargoCntrDO::getCntrSize).collect(Collectors.toList());
            if (cntrSizes.contains(CntrSizeEnum.size40.getValue()) || cntrSizes.contains(CntrSizeEnum.size45.getValue())) {
                return i18nsUtil.getMessage(SpecialCargoFlexiErrorCodeConstants.SPECIAL_CARGO_FLEXI_CNTR_SIZE_ERROR.getCode(), currentLocale);
            }
        }
        List<SpecialCargoCntrDO> cntrList = specialCargoCntrMapper.selectList(new LambdaQueryWrapper<SpecialCargoCntrDO>().eq(SpecialCargoCntrDO::getApplyId, applyId).eq(SpecialCargoCntrDO::getCntrType, CntrTypeEnum.FR.getValue()));
        if (CollectionUtil.isEmpty(cntrList)) {
            return StringUtils.EMPTY;
        }
        List<String> cntrSizes = cntrList.stream().map(SpecialCargoCntrDO::getCntrSize).collect(Collectors.toList());
        SpecialCargoVoyageDO voyageDo = specialCargoVoyageMapper.selectById(voyageId);
        List<String> portCodes = Arrays.asList(voyageDo.getPolCode(), voyageDo.getPodCode());
        Map<String, String> terminalMap = costChargeUtil.getVoyPortTerminalMap(voyageDo.getLaneCode(), voyageDo.getVoyageEx(), voyageDo.getVesselCode());
        List<String> terminalList = new ArrayList<>();
        if (terminalMap != null) {
            terminalList = new ArrayList<>(terminalMap.values());
        }
        LambdaQueryWrapper<PortTerminalMaxArgDO> queryWrapper = new LambdaQueryWrapper<PortTerminalMaxArgDO>()
                .eq(PortTerminalMaxArgDO::getCntrType, CntrTypeEnum.FR.getValue())
                .in(PortTerminalMaxArgDO::getPort, portCodes)
                .in(PortTerminalMaxArgDO::getCntrSize, cntrSizes)
                .eq(PortTerminalMaxArgDO::getEnable, Boolean.TRUE);
        if (CollectionUtil.isNotEmpty(terminalList)) {
            queryWrapper.in(PortTerminalMaxArgDO::getTerminalCode, terminalList);
        }
        List<PortTerminalMaxArgDO> portTerminalMaxArgDos = portTerminalMaxArgMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(portTerminalMaxArgDos)) {
            return StringUtils.EMPTY;
        }
        Map<String, List<PortTerminalMaxArgDO>> sizeMap = portTerminalMaxArgDos.stream().collect(Collectors.groupingBy(PortTerminalMaxArgDO::getCntrSize));
        for (SpecialCargoCntrDO cntr : cntrList) {
            String cntrSize = cntr.getCntrSize();
            String cntrType = cntr.getCntrType();
            List<PortTerminalMaxArgDO> maxArgDo = sizeMap.get(cntrSize);
            if (null != maxArgDo) {
                BigDecimal maxWgt = maxArgDo.stream().map(PortTerminalMaxArgDO::getMaxWgt).filter(Objects::nonNull).min(BigDecimal::compareTo).orElse(null);
                if (cntr.getGrossWgt().compareTo(maxWgt) > 0) {
                    if (CntrSizeEnum.size20.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_20FR_GROSS_WGT.getCode(), currentLocale);
                    } else if (CntrSizeEnum.size40.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_40FR_GROSS_WGT.getCode(), currentLocale);
                    } else {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_45FR_GROSS_WGT.getCode(), currentLocale);
                    }
                }
                SpecialCargoOogDO oogDo = specialCargoOogMapper.selectOne(new LambdaQueryWrapper<SpecialCargoOogDO>().eq(SpecialCargoOogDO::getCntrId, cntr.getId()));
                int length = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverallLength).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (length > DEFAULT_INT_VALUE && (oogDo.getOverallLength() > length)) {
                    if (CntrSizeEnum.size20.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_20FR_LENGTH.getCode(), currentLocale);
                    } else if (CntrSizeEnum.size40.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_40FR_LENGTH.getCode(), currentLocale);
                    } else {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_45FR_LENGTH.getCode(), currentLocale);
                    }
                }
                int width = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverallWidth).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (width > DEFAULT_INT_VALUE && (oogDo.getOverallWidth() > width)) {
                    if (CntrSizeEnum.size20.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_20FR_WIDTH.getCode(), currentLocale);
                    } else if (CntrSizeEnum.size40.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_40FR_WIDTH.getCode(), currentLocale);
                    } else {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_45FR_WIDTH.getCode(), currentLocale);
                    }
                }
                int height = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverallHeight).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (height > DEFAULT_INT_VALUE && (oogDo.getOverallHeight() > height)) {
                    if (CntrSizeEnum.size20.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_20FR_HEIGHT.getCode(), currentLocale);
                    } else if (CntrSizeEnum.size40.getValue().equals(cntrSize)) {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_40FR_HEIGHT.getCode(), currentLocale);
                    } else {
                        return i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_45FR_HEIGHT.getCode(), currentLocale);
                    }
                }
                int forward = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverForward).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (forward > DEFAULT_INT_VALUE && (oogDo.getOverForward() > forward)) {
                    String message = i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_FORWARD.getCode(), currentLocale);
                    return MessageFormat.format(message, cntrSize + cntrType);
                }
                int after = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverAfter).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (after > DEFAULT_INT_VALUE && (oogDo.getOverAfter() > after)) {
                    String message = i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_AFTER.getCode(), currentLocale);
                    return MessageFormat.format(message, cntrSize + cntrType);
                }
                int left = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverLeft).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (left > DEFAULT_INT_VALUE && (oogDo.getOverLeft() > left)) {
                    String message = i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_LEFT.getCode(), currentLocale);
                    return MessageFormat.format(message, cntrSize + cntrType);
                }
                int right = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverRight).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (right > DEFAULT_INT_VALUE && (oogDo.getOverRight() > right)) {
                    String message = i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_RIGHT.getCode(), currentLocale);
                    return MessageFormat.format(message, cntrSize + cntrType);
                }
                int overHeight = maxArgDo.stream().map(PortTerminalMaxArgDO::getOverHeight).filter(Objects::nonNull).mapToInt(Integer::intValue).min().orElse(0);
                if (overHeight > DEFAULT_INT_VALUE && (oogDo.getOverHeight() > overHeight)) {
                    String message = i18nsUtil.getMessage(SpecialCargoOogErrorCodeConstants.SPECIAL_CARGO_OOG_OVER_OVER_HEIGHT.getCode(), currentLocale);
                    return MessageFormat.format(message, cntrSize + cntrType);
                }

            }
        }
        return StringUtils.EMPTY;
    }
}
